package process

import (
	"dmsv/agent"
	"dmsv/call"
	"dmsv/common"
	"dmsv/models"
	"dmsv/session"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
)

var gDirectCallChan chan *call.CallInfo

func callcenterInit() {

	gDirectCallChan = make(chan *call.CallInfo, 1000)
	session.EnableDirectCall(gDirectCallChan)
	go directCallRoutine()
}

func directCallRoutine() {

	for {
		newCall := <-gDirectCallChan
		serviceOutCall(newCall)
	}
}

//直拨事件处理
func (c *Company) directCallRoutine(service *agent.AgentInfo, eventChan chan *session.CallBackData) {

	ringIsSend := false
	for {
		ev, ok := <-eventChan
		if !ok {
			break
		}

		switch ev.Event {
		case session.CALL_EVENT_FAIL:
			logs.Error("[%v] 外呼失败.", ev.Ssion.GetSessionId())
			//发送账单
			ev.Ssion.SendBill(gCallBack, common.ErrSystem)
		case session.CALL_EVENT_START:
			//直拨发通知
			ev.Ssion.CallOutRpt()
		case session.CALL_EVENT_RING:

			if ev.Dir == session.LEG_DIR_USER && false == ringIsSend {
				ev.Ssion.RingRpt("", true)
				ringIsSend = true
			}

		case session.CALL_EVENT_ANSWER:
			logs.Debug("[%v][%v] 接听", ev.CallId, ev.Dir)
			if ev.Dir == session.LEG_DIR_USER {
				fileName := createRecordName(ev.CallId, ev.Caller, ev.Callee)
				ev.Ssion.StartRecord(fileName)

				if c.satisfactionActive() {
					//开启满意度调查后，坐席挂机不能挂断用户
					ev.Ssion.HoldTheCall()
				}
				ev.Ssion.AnswerRpt("", "", true)
			}

		case session.CALL_EVENT_SATISFACTION:

			logs.Debug("[%v] 满意度调查按键处理:", ev.Ssion.GetSessionId())

			//满意度调查处理，放音后挂机
			media := common.MediaFullPath(c.GetAppId(), c.satisfaction.EndVoice)
			ev.Ssion.HangUpAfterPlay(media)

		case session.CALL_EVENT_DESTROY:

			hangInfo := ev.Data.(*session.HangInfo)
			logs.Debug("[%v]user call:%v is finished,通话时长:%v,挂机原因:%v",
				ev.CallId, ev.Ssion.GetServiceId(), hangInfo.Duration, hangInfo.Reason)

			ev.Ssion.SendBill(gCallBack, nil)
		case session.CALL_EVENT_HANGUP:

			logs.Debug("[%v]call is hangup", ev.CallId)
			hangUp, ok := ev.Data.(*session.HangInfo)
			if !ok {
				logs.Error("[%v]错误的挂机参数", ev.CallId)
				break
			}
			//坐席设置空闲
			service.SetPhoneFree(hangUp.Duration, false)

			if ev.Dir == session.LEG_DIR_USER {

				ev.Ssion.HangUp(nil)
				return
			} else {
				if hangUp.Duration == 0 {
					//主动取消呼叫
					return
				}

				logs.Debug("[%v]满意度相关配置:%v ", ev.Ssion.GetSessionId(), c.satisfaction)
				if false == c.satisfactionActive() {
					//未开启满意度调查，销毁通话 ,
					ev.Ssion.HangUp(nil)
				} else {
					//自动发送满意度
					if c.satisfactionAuto() {
						//自动启动满意度调查
						media := common.MediaFullPath(c.GetAppId(), c.satisfactionPlayFile())
						ev.Ssion.Satisfaction(media)
					} else {
						//未开启满意度配置的情况下，坐席挂机，挂断用户电话
						ev.Ssion.Destroy(common.SuccServiceHang)
					}
				}
			}
		default:
			logs.Debug("receive new event:%v", ev)
		}
	}

	return
}

func getAppInfo(companyId string) (*Company, error) {

	c, ok := gEterpriceHandle[companyId]
	if ok {
		return c, nil
	} else {
		return nil, fmt.Errorf("compnay:%v is not found", companyId)
	}
}

func serviceOutCall(call *call.CallInfo) {

	go func() {

		//查询坐席合法性
		a, err := agent.GetAgentInfo(call.Caller)
		if err != nil {
			logs.Debug("%v invalid call.agent:%v is not sign in:%v", call.CallId(), call.Caller, err.Error())
			call.ErrHangUp(common.ErrServiceNotSign)
			return
		}

		if models.JudgeBlackList(a.GetAppId(), call.Callee) {
			//黑名单 则挂机
			logs.Debug("%v 号码处于黑名单，暂停外呼", call.CallId(), call.Callee)
			call.ErrHangUp(common.ErrNumberBlack)
			return
		}

		//获取企业信息
		appInfo, err := getAppInfo(a.GetAppId())
		if err != nil {
			logs.Error("service out call failed:%v", err)
			call.ErrHangUp(common.ErrNumberBlack)
			return
		}

		display := a.GetDsplay()
		if display == "" {
			display = appInfo.number
		}

		//设置坐席电话忙
		a.SetPhoneBusy()
		//创建sessionId
		callId := createUUid()

		eventChan := make(chan *session.CallBackData, 10)

		//呼叫绑定坐席
		call.SetAgent(a)

		go appInfo.directCallRoutine(a, eventChan)

		//桥接外呼号码
		ss := session.DirectCall(a.GetAppId(), callId, display, call.Callee, call, eventChan)
		if ss != nil {
			//发送呼叫事件
			a.WsSendNewCall(ss.GetSessionId(), a.GetDsplay(), call.Callee, string(session.CALL_TYPE_OUT))
		}
	}()
}
